package util;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.jasper.tagplugins.jstl.core.Url;
import org.apache.log4j.Logger;

public class UrlConnectionUtil {

	// --------------------------------------------------------------------------------------
	// 公开方法：
	// 1. get(url:String , params:Map<String,String>)
	// 2. postForm(url:String ,params:Map<String,String>)
	// 3. postFile(url:String , filePath:String)
	// --------------------------------------------------------------------------------------

	/***
	 * HTTP get请求
	 * 
	 * @param url
	 * @param params
	 * @return
	 * @throws IOException
	 */
	public static String get(String url, Map<String, String> params)
			throws IOException {
		// 拼接字符串
		String finalUrl = concatUrl(url, params);
		URL uurl = new URL(finalUrl);
		// 创建HttpURLConnection对象
		HttpURLConnection conn = (HttpURLConnection) uurl.openConnection();
		// 设置：连接超时5s
		conn.setConnectTimeout(5000);
		// 设置：Get方式请求
		conn.setRequestMethod("GET");
		// Logger
		Logger.getLogger("console").info("客户端发送get请求：" + url);
		// 连接建立
		conn.connect();
		// /开始操作
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				conn.getInputStream()));
		// /将响应输出
		StringBuilder sb = new StringBuilder();
		String line;
		while ((line = reader.readLine()) != null) {
			sb.append(line).append("\r\n");
		}
		// 断开连接
		conn.disconnect();
		return sb.toString();
	}

	/**
	 * HTTP post 表单提交请求
	 * 
	 * @param url
	 * @param body
	 * @throws IOException
	 */
	public static String postForm(String url, Map<String, String> params)
			throws IOException {
		URL uurl = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) uurl.openConnection();
		conn.setRequestMethod("POST");
		conn.setConnectTimeout(5000);
		// /设置可写（默认可读）
		conn.setDoOutput(true);
		conn.setDoInput(true);
		conn.setRequestProperty("Content-Type",
				"application/x-www-form-urlencoded");
		conn.setRequestProperty("Charset", "UTF-8");
		// Post 请求不能使用缓存
		conn.setUseCaches(false);
		// conn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
		// 设置本Connection实例可自动重定向
		conn.setInstanceFollowRedirects(true);
		// 打开连接
		conn.connect();

		// /开始传输
		if (params != null && params.size() > 0) {
			DataOutputStream out = new DataOutputStream(conn.getOutputStream());

			Set<String> keys = params.keySet();
			Iterator<String> it = keys.iterator();
			StringBuilder sb1 = new StringBuilder();
			while (it.hasNext()) {
				String key = it.next();
				sb1.append(key + "="
						+ URLEncoder.encode(params.get(key), "UTF-8"));
				if (it.hasNext()) {
					sb1.append("&");
				}
			}
			// logger
			Logger.getLogger("console").info(
					"post body 参数： " + sb1.toString());
			// 传输body
			out.writeBytes(sb1.toString());
			// 关闭连接
			out.flush();
			out.close();
		}

		StringBuilder sb = new StringBuilder();
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				conn.getInputStream()));
		String line;
		while ((line = reader.readLine()) != null) {
			sb.append(line);
		}
		reader.close();
		// /最终断开连接
		conn.disconnect();
		return sb.toString();
	}

	/**
	 * post 文件上传
	 * 
	 * @param url
	 * @param filePath
	 * @throws IOException
	 */
	public static void postFile(String url, String fileName, String filePath)
			throws IOException {
		// boundary就是request头和上传文件内容的分隔符(可自定义任意一组字符串)
		String BOUNDARY = "******";
		// 用来标识payLoad+文件流的起始位置和终止位置(相当于一个协议,告诉你从哪开始,从哪结束)
		String preFix = ("\r\n--" + BOUNDARY + "--\r\n");

		HttpURLConnection conn = null;
		try {
			// (HttpConst.uploadImage 上传到服务器的地址
			URL uurl = new URL(url);
			conn = (HttpURLConnection) uurl.openConnection();
			conn.setConnectTimeout(5000);
			conn.setReadTimeout(30000);
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			// 设置请求方法
			conn.setRequestMethod("POST");
			// 设置header
			conn.setRequestProperty("Accept", "*/*");
			conn.setRequestProperty("Connection", "keep-alive");
			conn.setRequestProperty("Content-Type",
					"multipart/form-data; boundary=" + BOUNDARY);
			// 获取写输入流
			OutputStream out = new DataOutputStream(conn.getOutputStream());
			// 获取上传文件
			File file = new File(filePath);

			// 要上传的数据
			StringBuffer strBuf = new StringBuffer();

			// 标识payLoad + 文件流的起始位置
			strBuf.append(preFix);

			// 下面这三行代码,用来标识服务器表单接收文件的name和filename的格式
			// 在这里,我们是file和filename.后缀[后缀是必须的]。
			// 这里的fileName必须加个.jpg,因为后台会判断这个东西。
			// 这里的Content-Type的类型,必须与fileName的后缀一致。
			// 如果不太明白,可以问一下后台同事,反正这里的name和fileName得与后台协定！
			// 这里只要把.jpg改成.txt，把Content-Type改成上传文本的类型，就能上传txt文件了。
			strBuf.append("Content-Disposition: form-data; name=\"file\"; filename=\""
					+ fileName + "\"\r\n");
			strBuf.append("Content-Type: image/jpeg" + "\r\n\r\n");
			out.write(strBuf.toString().getBytes());

			// 获取文件流
			FileInputStream fileInputStream = new FileInputStream(file);
			DataInputStream inputStream = new DataInputStream(fileInputStream);

			// 每次上传文件的大小(文件会被拆成几份上传)
			int bytes = 0;
			// 计算上传进度
			float count = 0;
			// 获取文件总大小
			int fileSize = fileInputStream.available();
			// 每次上传的大小
			byte[] bufferOut = new byte[1024];
			// 上传文件
			while ((bytes = inputStream.read(bufferOut)) != -1) {
				// 上传文件(一份)
				out.write(bufferOut, 0, bytes);
				// 计算当前已上传的大小
				count += bytes;
				// 打印上传文件进度(已上传除以总大*100就是进度)
				Logger.getLogger("console").info(
						"progress:" + (count / fileSize * 100) + "%");
			}

			// 关闭文件流
			inputStream.close();

			// 标识payLoad + 文件流的结尾位置
			out.write(preFix.getBytes());

			// 至此上传代码完毕

			// 总结上传数据的流程：preFix + payLoad(标识服务器表单接收文件的格式) + 文件(以流的形式) + preFix
			// 文本与图片的不同,仅仅只在payLoad那一处的后缀的不同而已。

			// 输出所有数据到服务器
			out.flush();

			// 关闭网络输出流
			out.close();

			// 重新构造一个StringBuffer,用来存放从服务器获取到的数据
			strBuf = new StringBuffer();

			// 打开输入流 , 读取服务器返回的数据
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					conn.getInputStream()));

			String line;

			// 一行一行的读取服务器返回的数据
			while ((line = reader.readLine()) != null) {
				strBuf.append(line).append("\n");
			}

			// 关闭输入流
			reader.close();

			// 打印服务器返回的数据
			Logger.getLogger("console").info(
					"上传成功：" + strBuf.toString());
		} catch (Exception e) {
			Logger.getLogger("console").error(
					"上传图片出错:" + e.toString());
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
		}

	}

	// --------------------------------------------------------------------------------------
	// 私有实现
	// --------------------------------------------------------------------------------------

	private static String concatUrl(String url, Map<String, String> params) {
		StringBuilder sb = new StringBuilder();
		sb.append(url);

		if (params == null || params.size() == 0)
			return sb.toString();

		sb.append("?");
		Set<String> keys = params.keySet();
		Iterator<String> it = keys.iterator();
		while (it.hasNext()) {
			String key = it.next();
			try {
				sb.append(key).append("=")
						.append(URLEncoder.encode(params.get(key), "utf-8"));
			} catch (UnsupportedEncodingException e) {
				Logger.getLogger("console").error(
						"URLEncoder转UTF-8编码过程出错: " + e.getMessage());
				e.printStackTrace();
			}// 看情况使用：URLEncoder.encode("XXX", "utf-8");防中文乱码
			if (it.hasNext())
				sb.append("&");
		}
		return sb.toString();
	}

}
